/*
**作用：中转代理http POST/GET请求以实现跨域访问
**作者：江辉（fryeit@sohu.com）
**时间：2019-08-22
 */
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

func main() {
	port := flag.Int("port", 8089, "port default:8089")
	flag.Parse()
	http.HandleFunc("/", helloPage)
	http.HandleFunc("/proxyRequest", proxyPage)
	fmt.Print("CORS proxy server start. Port:")

	fmt.Println(*port)
	http.ListenAndServe(":"+strconv.Itoa(*port), nil)
}

func helloPage(res http.ResponseWriter, req *http.Request) {
	res.Write([]byte("CORS proxy server is working."))
}

func proxyPage(res http.ResponseWriter, req *http.Request) {

fmt.Println(req.Method)
	// 如果是OPTIONS请求，直接返回成功并允许跨域
	if req.Method == "OPTIONS" {
		fmt.Println(res.Header())
		// res.Header().Set("Content-Type", "application/json; charset=utf-8")
		res.Header().Set("access-control-allow-headers", req.Header.Get("access-control-Request-headers")) // 要啥给啥
		res.Header().Set("Access-Control-Allow-Origin", "*")
		res.WriteHeader(http.StatusOK)
		return
	}

	var realUrl string = ""

	// 代理请求的关键步骤，处理proxyRealUrl，在写请求时注意在原Header增加proxyRealUrl,值为请求真实地址，如果有自定义User-Agent则用proxyUser-Agent代替
	// 遍历原Header，取proxyRealUrl的值作为真实的请求地址，把proxyUser-Agent替换成User-Agent(由于某些浏览器禁止主动修改User-Agent)

	for kr, vr := range req.Header {
		if strings.EqualFold(kr, "proxyRealUrl") {
			realUrl = vr[0]
			delete(req.Header, kr)
		} else if strings.EqualFold(kr, "proxyUser-Agent") {
			delete(req.Header, kr)
			req.Header.Set("User-Agent", vr[0])
		} else if strings.EqualFold(kr, "delete-headers") { // 要删除掉不提交给真实请求的headers项 示例: "delete-headers": "User-Agent Origin"
			for _, h := range strings.Fields(vr[0]) {
				delete(req.Header, h)
			}
		}

	}
	fmt.Println(realUrl)

	// 以原请求建立新的真实请求
	reqs, err := http.NewRequest(req.Method, realUrl, req.Body)
	reqs.Header = req.Header


	// fmt.Println(len(req.Header))
	// fmt.Println(len(reqs.Header))

	client := http.DefaultClient
	// 执行真实的请求
	ress, err := client.Do(reqs)
	if err != nil {
		res.WriteHeader(http.StatusNotFound)
		fmt.Fprint(res, err)
		return
	}
	fmt.Println(ress)
	// 获取新的body
	bodyRes, err := ioutil.ReadAll(ress.Body)
	if err != nil {
		res.WriteHeader(http.StatusNotFound)
		fmt.Fprint(res, err)
		return
	}

	// 设置返回的header
	for k, vs := range ress.Header {
		for _, v := range vs {
			res.Header().Add(k, v)
		}
	}

	// 设置返回的cookie
	for _, value := range ress.Request.Cookies() {
		// fmt.Println(value.Value)
		res.Header().Add(value.Name, value.Value)
	}

	fmt.Println(req.Header.Get("access-control-Request-headers"))
	// 关键代码 修改结果Header允许返回的结果跨域
	// res.Header().Set("Content-Type", "application/json; charset=utf-8")
	res.Header().Set("access-control-allow-headers", req.Header.Get("access-control-Request-headers")) // 要啥给啥
	// res.Header().Set("access-control-allow-headers", "Authorization, Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, X-Requested-By, If-Modified-Since, X-File-Name, X-File-Type, Cache-Control, Origin, proxyrealurl, proxyUser-Agent, appInfo, token")
	res.Header().Set("Access-Control-Allow-Origin", "*")
	res.WriteHeader(ress.StatusCode)

	// fmt.Println(string(bodyRes[:]))
	res.Write(bodyRes)
}
